﻿using S7.Net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//using System.Threading.Tasks;

namespace GEMINI_OP110
{
    public class SimenesPLC
    {
        public Plc plc;
        public int cnt;
        private bool conectStatus = false;  //链接状态

        #region 连接状态 
        public bool ConectStatus  //链接状态属性，当值为True时，代表链接正常，
        {
            get//读的属性
            {
                return conectStatus;//返回值
            }
            set//写的属性
            {
                conectStatus = value;//重新赋值
            }
        }
        #endregion 

        #region 实例一个PLC
        public SimenesPLC(CpuType cpu, string IP, short rock, short solt)
        {
            plc = new Plc(cpu, IP, rock, solt);
        }
        #endregion

        #region 通过Ping链接PLC
        public void connectPLC()
        {
            try
            {
                cnt = cnt + 1;  //全局静态变量，线程执行的一个循环标志
                if (plc.IsAvailable == true && plc.IsConnected == true)  //当连接正常时，循环标志为0，不执行以下的几个if条件的内容
                {
                    cnt = 0;
                }

                if (plc.IsAvailable == false && plc.IsConnected == false && cnt == 1) //如果通信断开后在第1次线程进入时进行关闭PLC
                {
                    conectStatus = false;//通讯断开
                    plc.Close();

                }

                if (plc.IsAvailable == true && plc.IsConnected == false && cnt >= 3) //如果网络通(Ping通)且PLC没有连接成功能后的第3次线程进入时进行打开PLC。同时cnt=0; 程进入时只执行Ping不执行关闭PLC和打开PLC操作。
                {
                    cnt = 0;
                    int s = (int)plc.Open();
                    //FormPLC.textBox.Text = Convert.ToString(s);
                }
                if (cnt > 3) //防止cnt溢出
                {
                    cnt = 0;
                }

                if (plc.IsConnected == true)
                {
                    conectStatus = true;//已链接
                }
                else
                {
                    conectStatus = false;//未链接
                }
            }
            catch
            {

            }
        }
        #endregion

        #region 通过读取心跳链接PLC
        public void HeartConnectPLC(string readString)
        {
            bool HeartState = ConnState(readString);
            try
            {
                if (HeartState == false)
                {
                    if (conectStatus == true)
                    {
                        plc.Close();
                    }
                    conectStatus = false;

                    if (plc.IsAvailable == true)
                    {
                        int s = (int)plc.Open();
                        //FormPLC.textBox.Text = Convert.ToString(s);
                        if (plc.IsConnected == true)
                        {
                            conectStatus = true;//已链接
                        }
                    }

                }
                else
                {
                    conectStatus = true;
                }
            }
            catch
            {

            }
        }
        #endregion

        #region 读取PLC某个Boolen变量判断PLC通讯状态
        public bool ConnState(string readString /*读取字符串地址*/)
        {
            bool bolState = false;
            try
            {
                bool result = Convert.ToBoolean(plc.Read(readString));
                if (plc.LastErrorCode == 0)
                {
                    bolState = true;
                }
                else
                {
                    bolState = false;
                }
            }
            catch
            {
                bolState = false;
            }
            return bolState;
        }
        #endregion

        #region 读取多个变量

        public List<byte> ReadMultipleBytes(int numBytes, int db, int startByteAdr)//( 读取的字节数，如果要读取 DB1.DBW200，则为200)
        {
            List<byte> resultBytes = new List<byte>();
            int index = startByteAdr;
            while (numBytes > 0)
            {
                var maxToRead = (int)Math.Min(numBytes, 200);//不能大于200
                                                             //plc.ReadBytes(输入= 129输出 = 130内存 = 131数据块 = 132计时器 = 29计数器 = 28, 如果您想读取 DB1，则此字段为“ 1”, 如果要读取 DB1.DBW200，则为200, 读取的字节数)
                byte[] bytes = plc.ReadBytes(DataType.DataBlock, db, index, (int)maxToRead);
                if (bytes == null)
                    return new List<byte>();
                resultBytes.AddRange(bytes);
                numBytes -= maxToRead;
                index += maxToRead;
            }
            return resultBytes;
        }
        #endregion

        #region 读取多个字节
        public byte[] ReadBytes(int numBytes, int db, int startByteAdr)
        {
            byte[] bytes = plc.ReadBytes(DataType.DataBlock, db, startByteAdr, numBytes);
            return bytes;
        }
        #endregion

        #region 读取字符串,繁琐版，可以不用
        public string ReadStringBad(int numBytes, int db, int startByteAdr)
        {
            string outString = "";
            if (conectStatus == true)
            {
                try
                {
                    byte[] bytes = new byte[numBytes];
                    bytes = ReadBytes(numBytes, db, startByteAdr);
                    for (int i = 0; i <= numBytes - 1; i++)
                    {
                        byte S1 = (byte)bytes[i];
                        char S2 = (char)S1;
                        outString = outString + S2;
                    }

                }
                catch
                {
                    outString = "";
                }
            }
            return outString;
        }
        #endregion

        #region 读取字符串精简版  例：ReadStringGood(DataType.DataBlock, 1,24,20);//读取起始地址为DB1.DBB22的字符串，注意：此处起始地址=填字符串首地址+2
        public string ReadStringGood(DataType DataBlock, int db, int startByteAdr, int varCount)
        {
            string outString = "";
            if (conectStatus == true)
            {
                try
                {
                    outString = plc.Read(DataBlock, db, startByteAdr, VarType.String, varCount).ToString();

                }
                catch
                {
                    outString = "";
                }
            }
            return outString;
        }
        #endregion

        #region 读取一个字节 例：ReadByte(DataType.Memory ,1, 1).ToString();//读取MB1    ReadByte(DataType.DataBlock , 1, 1).ToString();//读取DB1.DBB1
        public byte ReadByte(DataType dataBlock, int db, int startByteAdr)
        {
            byte byte1 = 0;
            try
            {
                byte[] bytes = plc.ReadBytes(dataBlock, db, startByteAdr, 1);
                byte1 = bytes[0];
                return byte1;
            }
            catch
            {
                return byte1 = 0;
            }
        }
        #endregion

        #region 读取16位无符号整数
        public ushort readUshort(string readString/*读取字符串地址*/)
        {
            ushort result = 0;
            if (conectStatus == true)
            {
                try
                {
                    result = (ushort)plc.Read("readString");

                }
                catch
                {
                    result = 0;
                }
            }
            return result;

        }
        #endregion

        #region 读取16位有符号整数
        public short readInt(string readString/*读取字符串地址*/)
        {
            short result = 0;
            if (conectStatus == true)
            {
                try
                {
                    result = ((ushort)plc.Read(readString)).ConvertToShort();
                }
                catch
                {
                    result = 0;
                }
            }
            return result;
        }
        #endregion

        #region 读取双整数
        public int readDInt(string readString/*读取字符串地址*/)
        {
            int result = 0;
            if (conectStatus == true)
            {
                try
                {
                    result = ((uint)plc.Read(readString)).ConvertToInt();
                }
                catch
                {
                    result = 0;
                }
            }
            return result;
        }
        #endregion

        #region 读取实数
        public double readReal(string readString /*读取字符串地址*/)
        {
            double result = 0;
            if (conectStatus == true)
            {
                try
                {
                    result = ((uint)plc.Read(readString)).ConvertToDouble();

                }
                catch
                {
                    result = 0;
                }
            }
            return result;
        }
        #endregion

        #region 读取Boolen型变量  例:readBoolen("M0.0")   readBoolen("DB1.DBX0.0")
        public bool readBoolen(string readString/*读取字符串地址*/)
        {
            bool result = false;
            if (conectStatus == true)
            {
                try
                {
                    result = Convert.ToBoolean(plc.Read(readString));

                }
                catch
                {
                    result = false;
                }
            }
            return result;
        }
        #endregion

        #region 写入字符串函数
        public bool WriteString(CpuType cpu, DataType DataBlock/*数据块类型*/, int db, int startByteAdr/*起始地址*/, string stringWrite/*写入字符串*/, byte stringLength = 0/*字符总长度，只针对1200以上PLC，200不需要设置0*/)
        {
            bool result = false;
            int Lentgh = stringWrite.Length;
            ErrorCode errcode;
            byte[] vaule = new byte[Lentgh + 2];
            byte[] array = System.Text.Encoding.ASCII.GetBytes(stringWrite);
            if (conectStatus == true)
            {
                if (cpu == CpuType.S71200 || cpu == CpuType.S71500 || cpu == CpuType.S7300 || cpu == CpuType.S7400)
                {
                    vaule[0] = stringLength;
                    vaule[1] = (byte)Lentgh;
                    for (int i = 0; i <= Lentgh - 1; i++)
                    {
                        vaule[i + 2] = (byte)array[i];
                    }
                }
                else if (cpu == CpuType.S7200)
                {
                    vaule[0] = (byte)Lentgh;
                    for (int i = 0; i <= Lentgh - 1; i++)
                    {
                        vaule[i + 1] = (byte)array[i];
                    }

                }

                try
                {
                    errcode = plc.WriteBytes(DataBlock, db, startByteAdr, vaule);
                    if (errcode == 0)
                    {
                        result = true;
                    }
                    else
                    {
                        result = false;
                    }

                }
                catch
                {
                }
            }
            return result;
        }
        #endregion

        #region 写入Boolen型函数
        public bool WriteBoolen(string writeString, bool value)
        {
            bool result = false;
            ErrorCode errcode;
            int bolInt = 0;
            if (value == true)
            {
                bolInt = 1;
            }
            else
            {
                bolInt = 0;
            }
            if (conectStatus == true)
            {
                try
                {
                    errcode = plc.Write(writeString, bolInt);
                    if (errcode == 0)
                    {
                        result = true;
                    }
                    else
                    {
                        result = false;
                    }

                }
                catch
                {
                }
            }
            return result;
        }
        #endregion

        #region 写无符号8位整数
        public bool WriteByte(string writeString, byte value)
        {
            bool result = false;
            ErrorCode errcode;

            if (conectStatus == true)
            {
                try
                {
                    errcode = plc.Write(writeString, value);
                    if (errcode == 0)
                    {
                        result = true;
                    }
                    else
                    {
                        result = false;
                    }

                }
                catch
                {
                }
            }
            return result;
        }
        #endregion

        #region 写无符号16位整数
        public bool WriteWord(string writeString, ushort value)
        {
            bool result = false;
            ErrorCode errcode;

            if (conectStatus == true)
            {
                try
                {
                    errcode = plc.Write(writeString, value);
                    if (errcode == 0)
                    {
                        result = true;
                    }
                    else
                    {
                        result = false;
                    }

                }
                catch
                {
                }
            }
            return result;
        }
        #endregion

        #region 写有符号16位整数
        public bool WriteShort(string writeString, short value)
        {
            bool result = false;
            ErrorCode errcode;

            if (conectStatus == true)
            {
                try
                {
                    errcode = plc.Write(writeString, value);
                    if (errcode == 0)
                    {
                        result = true;
                    }
                    else
                    {
                        result = false;
                    }

                }
                catch
                {
                }
            }
            return result;
        }
        #endregion

        #region 写有符号32位整数
        public bool WriteInt(string writeString, int value)
        {
            bool result = false;
            ErrorCode errcode;

            if (conectStatus == true)
            {
                try
                {
                    errcode = plc.Write(writeString, value);
                    if (errcode == 0)
                    {
                        result = true;
                    }
                    else
                    {
                        result = false;
                    }

                }
                catch
                {
                }
            }
            return result;
        }
        #endregion

        #region 写实数函数
        public bool WriteReal(string writeString, double value)
        {
            bool result = false;
            ErrorCode errcode;

            if (conectStatus == true)
            {
                try
                {
                    errcode = plc.Write(writeString, value.ConvertToUInt());
                    if (errcode == 0)
                    {
                        result = true;
                    }
                    else
                    {
                        result = false;
                    }

                }
                catch
                {
                }
            }
            return result;
        }
        #endregion
    }
}
